package com.love.marriage.cloud.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.binarywang.wxpay.bean.request.WxPaySendMiniProgramRedpackRequest;
import com.github.binarywang.wxpay.bean.request.WxPaySendRedpackRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPaySendMiniProgramRedpackResult;
import com.github.binarywang.wxpay.bean.result.WxPaySendRedpackResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.google.common.collect.Maps;
import com.love.marriage.cloud.service.WechatService;
import com.love.marriage.cloud.service.WechatWithdrawService;
import com.love.marriage.cloud.vo.*;
import com.love.marriage.common.enums.ResultEnum;
import com.love.marriage.common.exceptions.SystemException;
import com.love.marriage.config.WeChatConfig;
import com.love.marriage.config.WeChatGzhConfig;
import com.love.marriage.userCommissionBalance.mapper.UserCommissionBalanceMapper;
import com.love.marriage.userCommissionBalance.service.CommissionCommonService;
import com.love.marriage.userCommissionBalance.vo.UserCommissionBalanceVo;
import com.love.marriage.userCommissionWithdrawal.entity.UserCommissionWithdrawal;
import com.love.marriage.userCommissionWithdrawal.service.UserCommissionWithdrawalService;
import com.love.marriage.userCommissionWithdrawal.vo.UserCommissionWithdrawalVo;
import com.love.marriage.userInfo.entity.UserInfo;
import com.love.marriage.userInfo.mapper.UserInfoMapper;
import com.love.marriage.userInfo.vo.UserInfoVo;
import com.love.marriage.userPartnerPreferences.service.UserPartnerPreferencesService;
import com.love.marriage.userPartnerPreferences.vo.UserPartnerVo;
import com.love.marriage.utils.RedisUtils;
import com.love.marriage.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.bean.subscribe.WxMpSubscribeMessage;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class WechatServiceImpl implements WechatService {

    @Autowired
    @Qualifier("miniAppPayService")
    private WxPayService wxPayService;

    @Autowired
    @Qualifier("gzhPayService")
    private WxPayService wxGzhPayService;

    private final UserInfoMapper userInfoMapper;

    private final WeChatConfig weChatConfig;

    private final WeChatGzhConfig weChatGzhConfig;

    private final WxMpService wxMpService;

    private final WxMaService wxMaService;

    private final UserPartnerPreferencesService userPartnerPreferencesService;

    private final RedisUtils redisUtils;

    private final UserCommissionBalanceMapper userCommissionBalanceMapper;

    private final WechatWithdrawService wechatWithdrawService;

    private final CommissionCommonService commissionCommonService;

    private final UserCommissionWithdrawalService userCommissionWithdrawalService;

    @Override
    public WxPayUnifiedOrderV3Result.JsapiResult unifiedOrder(Long userId, Integer amount, String type, String code, String desc) throws WxPayException {
        UserInfoVo userInfoVo = userInfoMapper.queryUserInfo(userId);
        if (userInfoVo == null) {
            throw new SystemException(ResultEnum.USER_NOT_EXIST);
        }
        if (userInfoVo.getWechatOpenid() == null) {
            throw new SystemException(ResultEnum.WECHAT_NOT_EXIST);
        }
        WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request();
        request.setDescription(desc);
        request.setOutTradeNo(code);
        request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(amount));
        request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(userInfoVo.getWechatOpenid()));
        request.setNotifyUrl(weChatConfig.getNotifyUrl());
        request.setAttach(type);
        // wxPayService 会自动生成签名并发送请求
        WxPayUnifiedOrderV3Result.JsapiResult orderV3 = wxPayService.createOrderV3(TradeTypeEnum.JSAPI, request);
        log.info("微信支付请求：{}，微信支付统一下单结果: {}", request, orderV3);

        if (orderV3 == null) {
            throw new SystemException(ResultEnum.SYSTEM_ERROR);
        }
        return orderV3;
    }

    public String getToken() throws WxErrorException {
        return wxMpService.getAccessToken();
    }

    public boolean sentUserMessage(String openId, Long userId, String userCode, String type) throws WxErrorException {
        log.info("sentUserMessage。参数openId:{},userId:{}, userCode:{}, type:{}",openId, userId, userCode, type);
        String token = getToken();
        List<WxMpTemplateData> dataList = Lists.newArrayList();
        String templateId = "";
        switch (type) {
            case "detail":
                dataList.add(new WxMpTemplateData("thing1", "丹身乐缘号" + userCode, "#A9A9A9"));
                dataList.add(new WxMpTemplateData("time2", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), "#A9A9A9"));
                templateId = weChatGzhConfig.getViewTemplateId();
                break;
            case "partner":
                dataList.add(new WxMpTemplateData("thing1", "今日推荐丹身乐缘号" + userCode, "#A9A9A9"));
                dataList.add(new WxMpTemplateData("time2", LocalDateTime.now().withHour(22).withMinute(0).withSecond(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), "#A9A9A9"));
                templateId = weChatGzhConfig.getViewTemplateId();
                break;
        }
        WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                .templateId(templateId)
                .toUser(openId)
                .url("https://api.weixin.qq.com/cgi-bin/message/subscribe/bizsend?access_token=" + token)
                .data(dataList)
                .miniProgram(new WxMpTemplateMessage.MiniProgram(weChatConfig.getAppId(), "/activity/userDetail?id=" + userId, true))
                .build();
        wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
        return true;
    }

    public boolean sentUserSubscribeMessage(String openId, Long userId, String userCode, String type) throws WxErrorException {
        String token = getToken();
        Map<String, String> dataMap = Maps.newHashMap();
        String templateId = "";
        switch (type) {
            case "detail":
                dataMap.put("thing2", "丹身乐缘号" + userCode + "刚刚查看了您的资料");
                dataMap.put("thing3", "\uD83D\uDC49点此查看\uD83D\uDC48");
                templateId = weChatGzhConfig.getSubViewTemplateId();
                break;
            case "partner":
                templateId = weChatGzhConfig.getSubPartnerTemplateId();
                break;
        }
        WxMpSubscribeMessage templateMessage = WxMpSubscribeMessage.builder()
                .templateId(templateId)
                .toUser(openId)
                .url("https://api.weixin.qq.com/cgi-bin/message/subscribe/bizsend?access_token=" + token)
                .dataMap(dataMap)
                .miniProgram(new WxMpSubscribeMessage.MiniProgram(weChatConfig.getAppId(), "/activity/userDetail?id=" + userId, true))
                .build();
        wxMpService.getSubscribeMsgService().send(templateMessage);
        return true;
    }

    @Override
    public boolean checkSignature(String signature, String timestamp, String nonce) {
        try {
            // 1. 将 token、timestamp、nonce 按字典序排序
            String[] params = new String[]{weChatGzhConfig.getToken(), timestamp, nonce};
            Arrays.sort(params);

            // 2. 将排序后的参数拼接成一个字符串
            StringBuilder content = new StringBuilder();
            for (String param : params) {
                content.append(param);
            }

            // 3. 对拼接后的字符串进行 SHA1 加密
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] digest = md.digest(content.toString().getBytes());

            // 4. 将加密后的字节数组转换为十六进制字符串
            StringBuilder hexString = new StringBuilder();
            for (byte b : digest) {
                String hex = Integer.toHexString(b & 0xFF);
                if (hex.length() == 1) {
                    hexString.append('0'); // 单字符补0
                }
                hexString.append(hex);
            }

            // 5. 将生成的签名与传入的 signature 对比，判断请求是否来自微信服务器
            return hexString.toString().equals(signature);

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public Boolean gzhCallBack(HttpServletRequest request) throws ParserConfigurationException, IOException, SAXException, WxErrorException {
        // 假设我们已解析了微信回调 XML 并获得了用户的 openid 和事件类型
        // 解析 XML 获取 openid 和事件类型
        String openid = null;
        String eventType = null;

        InputStream inputStream = request.getInputStream();
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(inputStream);
        Element root = document.getDocumentElement();

        // 从 XML 中提取 openid 和事件类型
        openid = root.getElementsByTagName("FromUserName").item(0).getTextContent();
        eventType = root.getElementsByTagName("Event").item(0).getTextContent();

        log.info("gzh call back info : openid: {}, eventType: {}, {}", openid, eventType, JSONObject.toJSONString(root));
        if ("subscribe".equals(eventType) || "unsubscribe".equals(eventType)) {
            String unionId = "";
            switch (eventType) {
                case "unsubscribe":
                    LambdaQueryWrapper<UserInfo> query = Wrappers.<UserInfo>lambdaQuery()
                            .eq(UserInfo::getWechatGzhOpenid, openid)
                            .eq(UserInfo::getDeleteFlag, 0);
                    List<UserInfo> list = userInfoMapper.selectList(query);
                    if (list != null && !list.isEmpty()) {
                        unionId = list.get(0).getWechatUnionid();
                    }
                    openid = null;
                    break;
                case "subscribe":
                    WxMpUser wxMpUser = wxMpService.getUserService().userInfo(openid);
                    unionId = wxMpUser.getUnionId();
                    break;
            }
            log.info("unionId: {}", unionId);
            if (StringUtils.isBlank(unionId)) {
                return false;
            }
            LambdaQueryWrapper<UserInfo> query = Wrappers.<UserInfo>lambdaQuery()
                    .eq(UserInfo::getWechatUnionid, unionId)
                    .eq(UserInfo::getDeleteFlag, 0)
                    .orderByDesc(UserInfo::getOperateTime)
                    .last("limit 1");
            UserInfo db = userInfoMapper.selectOne(query);
            if (db == null) {
                return false;
            }
            db.setWechatGzhOpenid(openid);
            userInfoMapper.updateById(db);
        }
        return true;
    }

    @Override
    public boolean sentUserPartnerMessageInfo() throws WxErrorException {
        // 查找关注公告号的用户
        List<UserInfoVo> userInfoVoList = userInfoMapper.queryNoticeUserInfo();
        if (userInfoVoList == null || userInfoVoList.isEmpty()) {
            return true;
        }
        log.info("查找关注公告号的用户数量:{}，信息{}", userInfoVoList.size(), JSONObject.toJSONString(userInfoVoList));
        // 针对一个微信关联多个手机号的情况，只发送一次消息
        List<String> sendWechatOpenids = Lists.newArrayList();
        for (UserInfoVo userInfoVo : userInfoVoList) {
            if (StringUtils.isBlank(userInfoVo.getWechatGzhOpenid()) || sendWechatOpenids.contains(userInfoVo.getWechatGzhOpenid())) {
                continue;
            }
            log.info("发送匹配提醒");
            // 查询用户匹配信息（要求分数大于等于3）
            List<UserPartnerVo> userPartnerVos = userPartnerPreferencesService.queryReferenceList(userInfoVo.getId(), 1);
            log.info("用户匹配信息:{}", JSONObject.toJSONString(userPartnerVos));
            if (userPartnerVos == null || userPartnerVos.isEmpty()) {
                continue;
            }
            UserPartnerVo userPartnerVo = userPartnerVos.get(0);
            // 发送消息
            sentUserMessage(userInfoVo.getWechatGzhOpenid(), userPartnerVo.getId(), userPartnerVo.getCode(), "partner");
            sendWechatOpenids.add(userInfoVo.getWechatGzhOpenid());
        }
        return true;
    }

    @Override
    public Map<String, String> withdrawMoneyToWeChat(WithdrawVo withdrawVo) throws Exception {
        if (withdrawVo == null || withdrawVo.getAmount() == null || withdrawVo.getAmount().compareTo(new BigDecimal("0.1")) < 0) {
            throw new SystemException("500", "提现金额不能为空或小于0.1！");
        }
        if (withdrawVo.getAmount().compareTo(new BigDecimal("200")) > 0) {
            throw new SystemException("500", "提现金额不能超过200元！");
        }
        UserInfoVo userInfoVo = userInfoMapper.queryUserInfo(withdrawVo.getUserId());
        if (userInfoVo == null || StringUtils.isBlank(userInfoVo.getWechatOpenid())) {
            throw new SystemException("500", "请先微信登录！");
        }
        // 校验用户余额是否充足
        UserCommissionBalanceVo userCommissionBalanceVo = userCommissionBalanceMapper.queryTotalCommissionByUserId(withdrawVo.getUserId());
        if (userCommissionBalanceVo == null || userCommissionBalanceVo.getCurrentBalance().compareTo(withdrawVo.getAmount()) < 0) {
            throw new SystemException(ResultEnum.USER_NO_ENOUGH_WITH_BALANCE);
        }
        int newAmount = withdrawVo.getAmount().multiply(new BigDecimal("100")).setScale(0, RoundingMode.DOWN).intValueExact();
        BigDecimal subtract = new BigDecimal(String.valueOf(newAmount)).divide(new BigDecimal("100"));
        String partnerTradeNo = generate("Pay");
        log.info("用户体现信息,用户id:{},用户信息：{}，商户订单编码：{}，体现金额：{}", withdrawVo.getUserId(), JSONObject.toJSONString(userInfoVo), partnerTradeNo, withdrawVo.getAmount());
        Map<String, String> res = wechatWithdrawService.withdrawToWeChat(userInfoVo.getWechatOpenid(), partnerTradeNo, newAmount, "提现");
        UserCommissionWithdrawal userCommissionWithdrawal = commissionCommonService.withdrawalCommission(withdrawVo.getUserId(), subtract, partnerTradeNo);
        res.put("commissionWithdrawId", String.valueOf(userCommissionWithdrawal.getId()));
        return res;
    }

    @Override
    public Boolean cancelWithdrawToWeChat(Long id, String status) throws WxPayException {
        UserCommissionWithdrawalVo dbVo = userCommissionWithdrawalService.queryUserCommissionWithdrawal(id);
        if (dbVo == null || !"PENDING".equals(dbVo.getStatus())) {
            log.error("提现记录不存在！");
            return false;
        }
        Map<String, String> res = wechatWithdrawService.cancelTransferByOutBillNo(dbVo.getPartnerTradeNo());
        log.info("取消提现结果：{}", JSONObject.toJSONString(res));
        return true;
    }

    @Override
    public CheckVo secCheck(CheckVo checkVo) throws Exception {
        return secCheck(checkVo, false);
    }

    /**
     * WeChat content security check with performance optimization
     * 
     * @param checkVo Security check request
     * @param stopOnFirstFailure Whether to stop processing when first check fails
     * @return CheckVo with results
     * @throws Exception when validation fails or system error occurs
     */
    public CheckVo secCheck(CheckVo checkVo, boolean stopOnFirstFailure) throws Exception {
        // Input validation
        if (checkVo == null || checkVo.getUserId() == null) {
            throw new SystemException("500", "用户ID不能为空！");
        }
        if (checkVo.getCheckInfoList() == null || checkVo.getCheckInfoList().isEmpty()) {
            throw new SystemException("500", "请输入要校验的内容！");
        }

        // User validation
        UserInfoVo userInfoVo = userInfoMapper.queryUserInfo(checkVo.getUserId());
        if (userInfoVo == null || StringUtils.isBlank(userInfoVo.getWechatOpenid())) {
            throw new SystemException("500", "请先微信登录！");
        }

        log.info("Starting security check for user: {}, items: {}", checkVo.getUserId(), checkVo.getCheckInfoList().size());
        long startTime = System.currentTimeMillis();

        try {
            // Process checks in parallel for better performance
            List<CompletableFuture<CheckInfo>> futures = checkVo.getCheckInfoList().stream()
                    .map(checkInfo -> CompletableFuture.supplyAsync(() -> {
                        try {
                            return processCheckInfo(checkInfo, userInfoVo.getWechatOpenid());
                        } catch (Exception e) {
                            log.error("Error processing check info: {}", e.getMessage(), e);
                            checkInfo.setCheckRes(false);
                            checkInfo.setMessage("处理异常: " + e.getMessage());
                            return checkInfo;
                        }
                    }))
                    .collect(Collectors.toList());

            // Wait for all checks to complete or handle early termination
            boolean allPassed = true;
            for (int i = 0; i < futures.size(); i++) {
                CheckInfo result = futures.get(i).join();
                checkVo.getCheckInfoList().set(i, result);
                
                if (!result.getCheckRes()) {
                    allPassed = false;
                    if (stopOnFirstFailure) {
                        // Cancel remaining futures if early termination is enabled
                        for (int j = i + 1; j < futures.size(); j++) {
                            futures.get(j).cancel(true);
                            CheckInfo remainingCheck = checkVo.getCheckInfoList().get(j);
                            remainingCheck.setCheckRes(false);
                            remainingCheck.setMessage("已跳过检查");
                        }
                        break;
                    }
                }
            }

            checkVo.setResult(allPassed);
            long duration = System.currentTimeMillis() - startTime;
            log.info("Security check completed for user: {}, result: {}, duration: {}ms, detailed results: {}", 
                    checkVo.getUserId(), allPassed, duration, JSONObject.toJSONString(checkVo.getCheckInfoList()));
            
            return checkVo;
            
        } catch (Exception e) {
            long duration = System.currentTimeMillis() - startTime;
            log.error("Security check failed for user: {}, duration: {}ms, error: {}", 
                    checkVo.getUserId(), duration, e.getMessage(), e);
            throw new SystemException("500", "安全检查失败: " + e.getMessage());
        }
    }

    /**
     * Process individual check info item
     * 
     * @param checkInfo The check item to process
     * @param wechatOpenid User's WeChat openid
     * @return Processed CheckInfo with results
     * @throws Exception when check fails
     */
    private CheckInfo processCheckInfo(CheckInfo checkInfo, String wechatOpenid) throws Exception {
        if (checkInfo == null || StringUtils.isBlank(checkInfo.getCheckType())) {
            if (checkInfo == null) {
                checkInfo = new CheckInfo();
            }
            checkInfo.setCheckRes(false);
            checkInfo.setMessage("检查类型不能为空");
            return checkInfo;
        }

        if (StringUtils.isBlank(checkInfo.getContent())) {
            checkInfo.setCheckRes(false);
            checkInfo.setMessage("检查内容不能为空");
            return checkInfo;
        }

        try {
            switch (checkInfo.getCheckType().toLowerCase()) {
                case "msg":
                    msgSecCheck(checkInfo.getContent(), 4, wechatOpenid, null, null, null, checkInfo);
                    break;
                case "img":
                    int mediaType = checkInfo.getMediaType() != null ? checkInfo.getMediaType() : 2;
                    mediaCheckAsync(checkInfo.getContent(), mediaType, 4, wechatOpenid, checkInfo);
                    break;
                default:
                    checkInfo.setCheckRes(false);
                    checkInfo.setMessage("不支持的检测类型: " + checkInfo.getCheckType());
                    log.warn("Unsupported check type: {}", checkInfo.getCheckType());
                    break;
            }
        } catch (WxErrorException e) {
            log.error("WeChat API error for check type {}: {}", checkInfo.getCheckType(), e.getError().getErrorMsg());
            checkInfo.setCheckRes(false);
            checkInfo.setMessage(e.getError().getErrorMsg());
        } catch (Exception e) {
            log.error("Unexpected error during security check: {}", e.getMessage(), e);
            checkInfo.setCheckRes(false);
            checkInfo.setMessage("检查过程中发生异常: " + e.getMessage());
        }

        return checkInfo;
    }

    /**
     * 文本内容检测
     *
     * @param content 需要检测的文本内容
     * @return 检测是否通过
     */
    /**
     * 检查文本内容是否安全
     *
     * @param content   需要检查的文本内容，UTF-8编码，最多2500字
     * @param scene     场景枚举值（1 资料；2 评论；3 论坛；4 社交日志）
     * @param openid    用户的openid（用户需在近两小时访问过小程序）
     * @param title     文本标题，UTF-8编码（可选）
     * @param nickname  用户昵称，UTF-8编码（可选）
     * @param signature 个性签名，UTF-8编码，仅在资料类场景有效（scene=1，可选）
     * @return 如果内容安全返回 true，否则返回 false
     * @throws WxErrorException 微信接口错误异常
     */
    public boolean msgSecCheck(String content, int scene, String openid, String title, String nickname, String signature, CheckInfo checkInfo) throws WxErrorException {
        // 参数校验
        if (content == null || content.isEmpty()) {
            checkInfo.setCheckRes(false);
            checkInfo.setMessage("内容不能为空");
            return false;
        }
        if (content.length() > 2500) {
            checkInfo.setCheckRes(false);
            checkInfo.setMessage("内容长度超过2500字");
            return false;
        }
        // 获取 access token
        String accessToken = wxMaService.getAccessToken();
        // 构建 API 请求 URL
        String url = "https://api.weixin.qq.com/wxa/msg_sec_check?access_token=" + accessToken;
        // 构建请求数据
        Map<String, Object> requestData = new HashMap<>();
        requestData.put("content", content);
        requestData.put("version", 2);
        requestData.put("scene", scene);
        requestData.put("openid", openid);
        if (title != null && !title.isEmpty()) {
            requestData.put("title", title);
        }
        if (nickname != null && !nickname.isEmpty()) {
            requestData.put("nickname", nickname);
        }
        if (signature != null && !signature.isEmpty()) {
            requestData.put("signature", signature);
        }
        // 使用 try-with-resources 确保资源关闭
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost httpPost = new HttpPost(url);
            // 设置请求头
            httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
            // 将请求数据转换为 JSON 字符串
            String json = JSONObject.toJSONString(requestData);
            // 设置请求体
            httpPost.setEntity(new StringEntity(json, "UTF-8"));
            log.info("发送msgSecCheck请求: {}", json);
            // 执行请求
            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                // 解析响应
                HttpEntity entity = response.getEntity();
                if (entity == null) {
                    log.error("响应为空");
                    checkInfo.setCheckRes(false);
                    checkInfo.setMessage("响应为空");
                    return false;
                }
                String responseString = EntityUtils.toString(entity, "UTF-8");
                log.info("收到msgSecCheck响应: {}", responseString);
                JSONObject responseJson = JSONObject.parseObject(responseString);

                // 检查返回的错误码
                int errcode = responseJson.getIntValue("errcode");
                if (errcode == 0) {
                    String result = responseJson.getString("result");
                    // 内容安全
                    log.info("内容安全: {}", responseJson.getString("errmsg"));
                    checkInfo.setCheckRes(true);
                    checkInfo.setMessage(result);
                    return true;
                } else {
                    // 内容不安全，记录错误信息
                    String errmsg = responseJson.getString("errmsg");
                    checkInfo.setCheckRes(false);
                    checkInfo.setMessage(String.format("内容不安全: errcode=%s, errmsg=%s", errcode, errmsg));
                    // 根据需求，您可以进一步解析 detail 和 result 字段
                    return false;
                }
            }
        } catch (IOException e) {
            // 记录异常信息
            log.error("消息安全检查请求失败", e);
            checkInfo.setCheckRes(false);
            checkInfo.setMessage(String.format("消息安全检查请求失败:%s", e.getMessage()));
            return false;
        }
    }

    public boolean mediaCheckAsync(String mediaUrl, int mediaType, int scene, String openid, CheckInfo checkInfo) throws WxErrorException {
        // 参数校验
        if (mediaUrl == null || mediaUrl.isEmpty()) {
            checkInfo.setCheckRes(false);
            checkInfo.setMessage("文件地址不能为空");
            return false;
        }

        // 获取 access token
        String accessToken = wxMaService.getAccessToken();

        // 构建 API 请求 URL
        String url = String.format("https://api.weixin.qq.com/wxa/media_check_async?access_token=%s", accessToken);

        // 构建请求数据
        Map<String, Object> requestData = new HashMap<>();
        requestData.put("media_url", mediaUrl);
        requestData.put("media_type", mediaType);
        requestData.put("version", 2);
        requestData.put("scene", scene);
        requestData.put("openid", openid);

        String json = JSONObject.toJSONString(requestData);
        log.debug("发送mediaCheckAsync请求: {}", json);

        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost httpPost = new HttpPost(url);
            // 设置请求头
            httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
            // 设置请求体
            httpPost.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON));

            // 执行请求
            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                // 解析响应
                HttpEntity entity = response.getEntity();
                if (entity == null) {
                    checkInfo.setCheckRes(false);
                    checkInfo.setMessage("响应为空");
                    return false;
                }

                String responseString = EntityUtils.toString(entity, "UTF-8");
                log.debug("收到mediaCheckAsync响应: {}", responseString);

                JSONObject responseJson = JSONObject.parseObject(responseString);

                // 检查返回的错误码
                int errcode = responseJson.getIntValue("errcode");
                String errmsg = responseJson.getString("errmsg");

                if (errcode == 0) {
                    String trace_id = responseJson.getString("trace_id");
                    log.info(JSONObject.toJSONString(responseJson));
                    checkInfo.setCheckRes(true);
                    checkInfo.setMessage(trace_id);
                    return true;
                } else {
                    // 内容不安全，记录错误信息
                    checkInfo.setCheckRes(false);
                    checkInfo.setMessage(String.format("内容不安全: errcode=%s, errmsg=%s", errcode, errmsg));
                    // 根据需求，您可以进一步解析 detail 和 result 字段
                    return false;
                }
            }
        } catch (IOException e) {
            // 记录异常信息
            log.error("媒体内容校验请求失败", e);
            checkInfo.setCheckRes(false);
            checkInfo.setMessage("媒体内容校验请求失败");
            return false;
        }
    }

    public boolean verifyURL(String signature, String timestamp, String nonce, String echostr, HttpServletResponse response) throws IOException {
        String token = weChatConfig.getSecCheckToken();
        String[] arr = {token, timestamp, nonce};
        Arrays.sort(arr);
        StringBuilder sb = new StringBuilder();
        for (String s : arr) {
            sb.append(s);
        }
        String tempStr = DigestUtils.sha1Hex(sb.toString());
        if (tempStr.equals(signature)) {
            response.getWriter().write(echostr);
        } else {
            response.getWriter().write("Invalid signature");
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        }
        return true;
    }

    @Override
    public void secCheckCallback(String requestBody, String signature, String timestamp, String nonce, String encryptType, String msgSignature, HttpServletResponse response) throws IOException {
        String token = weChatConfig.getSecCheckToken();
        String encodingAESKey = weChatConfig.getSecCheckAesKey();
        String appid = weChatConfig.getAppId();

        String responseStr = "success"; // 默认回复
        log.info("================微信校验图片返回结果=====================：{}", JSONObject.toJSONString(requestBody));
        if ("aes".equalsIgnoreCase(encryptType)) {
            // 安全模式，消息加密
            if (msgSignature == null) {
                response.getWriter().write("Invalid message signature");
                return;
            }

            // 校验签名
            String[] arr = {token, timestamp, nonce, requestBody};
            Arrays.sort(arr);
            String tempStr = DigestUtils.sha1Hex(String.join("", arr));
            if (!tempStr.equals(msgSignature)) {
                response.getWriter().write("Invalid message signature");
                return;
            }

//            // 解密消息
//            String decryptedMsg = WeChatCryptUtil.decrypt(requestBody, encodingAESKey, appid);
//
//            // 示例回复消息
//            String replyMsg = "{\"demo_resp\":\"good luck\"}";
//
//            // 加密回复消息
//            String encryptedReply = WeChatCryptUtil.encrypt(replyMsg, encodingAESKey, appid);
//            // 生成 MsgSignature
//            String msgSig = DigestUtils.sha1Hex(token + timestamp + nonce + encryptedReply);
//            // 构造回复包
//            String replyJson = String.format("{\"Encrypt\":\"%s\",\"MsgSignature\":\"%s\",\"TimeStamp\":%s,\"Nonce\":\"%s\"}",
//                    encryptedReply, msgSig, timestamp, nonce);
//            responseStr = replyJson;
        } else {
            // 解析 decryptedMsg
            JSONObject res = JSONObject.parseObject(requestBody);
            Integer errcode = res.getInteger("errcode");
            String errmsg = res.getString("errmsg");
            String traceId = res.getString("trace_id");
            JSONObject result = res.getJSONObject("result");
            if (errcode != null && errcode == 0 && "ok".equalsIgnoreCase(errmsg)) {
                // 存储到 Redis 中，设置过期时间为15分钟（900秒）
                redisUtils.setEx(traceId, result.toJSONString(), 15, TimeUnit.MINUTES);
                log.info("Stored traceId={} with result={} to Redis", traceId, result.toJSONString());
            } else {
                redisUtils.setEx(traceId, result.toJSONString(), 15, TimeUnit.MINUTES);
            }
            // 回复消息
            responseStr = "success";
        }
        response.getWriter().write(responseStr);
    }

    @Override
    public Map<String, String> getImgResult(List<String> traceIds) {
        if (traceIds == null || traceIds.isEmpty()) {
            return null;
        }
        traceIds.forEach(item -> {
            String value = redisUtils.get(item);
            if (StringUtils.isBlank(value)) {
                throw new SystemException("800088", "微信暂时没解析完成");
            }
        });

        return traceIds.parallelStream()
                .collect(Collectors.toMap(
                        traceId -> traceId,                 // Key mapper
                        traceId -> {
                            String value = redisUtils.get(traceId);
                            return value != null ? value : ""; // Replace `defaultValue` with your default
                        }
                ));

    }

    /**
     * 生成商户订单号（符合微信支付规范）
     *
     * @param prefix 业务前缀（例如：PAY、ORDER）
     * @return 商户订单号（格式：前缀 + 时间戳 + 随机数，总长度 ≤32位）
     */
    public static String generate(String prefix) {
        // 1. 获取当前时间戳（毫秒级，13位）
        long timestamp = System.currentTimeMillis();

        // 2. 生成4位随机数（范围：1000~9999）
        int randomSuffix = ThreadLocalRandom.current().nextInt(1000, 10000);

        // 3. 拼接订单号
        return String.format("%s%d%d", prefix, timestamp, randomSuffix);
    }

    // 发送企业付款（红包）
    @Override
    public RedPacketResultVo sendRedPacket(RedPacketVo redPacketVo) throws WxPayException {
        if (BigDecimal.ZERO.compareTo(redPacketVo.getAmount()) >= 0) {
            throw new SystemException("500", "金额不能小于等于0");
        }
        UserInfoVo userInfoVo = userInfoMapper.queryUserInfo(redPacketVo.getUserId());
        if (userInfoVo == null || StringUtils.isBlank(userInfoVo.getWechatGzhOpenid())) {
            throw new SystemException("500", "请先微信登录！");
        }
        // 添加收款用户
        WxPaySendRedpackRequest wxPaySendRedpackRequest = new WxPaySendRedpackRequest();
        wxPaySendRedpackRequest.setReOpenid(userInfoVo.getWechatGzhOpenid()); // 接收者openid
        wxPaySendRedpackRequest.setTotalAmount(redPacketVo.getAmount().multiply(new BigDecimal("100")).intValue()); // 金额(分)
        wxPaySendRedpackRequest.setTotalNum(1); // 默认1人
        wxPaySendRedpackRequest.setWishing(redPacketVo.getWishing()); // 祝福语
        wxPaySendRedpackRequest.setActName(redPacketVo.getActName()); // 活动名称
        wxPaySendRedpackRequest.setSendName("丹身乐缘"); // 商户名
        wxPaySendRedpackRequest.setMchBillNo(redPacketVo.getMchBillNo()); // 订单号
        wxPaySendRedpackRequest.setRemark(redPacketVo.getRemark());
//        wxPaySendRedpackRequest.setSceneId("PRODUCT_2");
        // 调用API
        WxPaySendRedpackResult response = wxGzhPayService.getRedpackService().sendRedpack(wxPaySendRedpackRequest);
        RedPacketResultVo redPacketResultVo = new RedPacketResultVo();
        redPacketResultVo.setReturnCode(response.getReturnCode());
        redPacketResultVo.setReturnMsg(response.getReturnMsg());
        redPacketResultVo.setResultCode(response.getResultCode());
        redPacketResultVo.setErrCode(response.getErrCode());
        redPacketResultVo.setErrCodeDes(response.getErrCodeDes());
        return redPacketResultVo;
    }

    @Override
    public RedPacketResultVo sendMinProgramRedPacket(RedPacketVo redPacketVo) {
        UserInfoVo userInfoVo = userInfoMapper.queryUserInfo(redPacketVo.getUserId());
        if (userInfoVo == null || StringUtils.isBlank(userInfoVo.getWechatOpenid())) {
            throw new SystemException("500", "请先微信登录！");
        }
        // 添加收款用户
        WxPaySendMiniProgramRedpackRequest wxPaySendMiniProgramRedpackRequest = new WxPaySendMiniProgramRedpackRequest();
        wxPaySendMiniProgramRedpackRequest.setReOpenid(userInfoVo.getWechatOpenid()); // 接收者openid
        wxPaySendMiniProgramRedpackRequest.setTotalAmount(3); // 金额(分)
        wxPaySendMiniProgramRedpackRequest.setTotalNum(1); // 默认1人
        wxPaySendMiniProgramRedpackRequest.setWishing("祝福语"); // 祝福语
        wxPaySendMiniProgramRedpackRequest.setActName("促销活动"); // 活动名称
        wxPaySendMiniProgramRedpackRequest.setSendName("商户名称"); // 商户名
        wxPaySendMiniProgramRedpackRequest.setMchBillNo("R" + System.currentTimeMillis()); // 订单号
        // 调用API
        try {
            WxPaySendMiniProgramRedpackResult response = wxGzhPayService.getRedpackService().sendMiniProgramRedpack(wxPaySendMiniProgramRedpackRequest);
            RedPacketResultVo redPacketResultVo = new RedPacketResultVo();
            redPacketResultVo.setReturnCode(response.getReturnCode());
            redPacketResultVo.setReturnMsg(response.getReturnMsg());
            redPacketResultVo.setResultCode(response.getResultCode());
            redPacketResultVo.setErrCode(response.getErrCode());
            redPacketResultVo.setErrCodeDes(response.getErrCodeDes());
            return redPacketResultVo;
        } catch (Exception e) {
            throw new SystemException("500", "付款失败: " + e.getMessage());
        }
    }

}
